/******************************************************************************
* 	Copyright (c) 2007-2008 All rights reserved
*		Asemantics S.r.l
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer. 
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution,
*    if any, must include the following acknowledgment:
*       "This product includes software developed by 
*	 Asemantics S.r.l."
*    Alternately, this acknowledgment may appear in the software itself,
*    if and wherever such third-party acknowledgments normally appear.
*
* 4. All advertising materials mentioning features or use of this software
*    must display the following acknowledgement:
*    This product includes software developed by Asemantics S.r.l.
*    the Semantic Web company, Rome, London, Leiden and its contributors. 
*
* 5. Neither the name of the company nor the names of its contributors
*    may be used to endorse or promote products derived from this software
*    without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Author: Andrea Marchesini - baku@asemantics.com
*
******************************************************************************/

#include "config.h"

#include <controller.h>
#include <iostring.h>
#include <http.h>

/* Functions for the requests: */
static GString *http_request_info (TBGlobal * data, gchar ** subparts,
				   GList * keyvalue);
static GString *http_request_list (TBGlobal * data, gchar ** subparts,
				   GList * keyvalue);
static GString *http_request_exec (TBGlobal * data, gchar ** subparts,
				   GList * keyvalue);

#ifdef TB_DEBUG
static GString *http_request_debug (TBGlobal * data, gchar ** subparts,
				    GList * keyvalue);
#endif

TBHttpRequest tb_http_requests[] = {
  {"", http_request_info},
  {"list", http_request_list},
  {"exec", http_request_exec},

#ifdef TB_DEBUG
  {"debug", http_request_debug},
#endif

  {NULL}
};

/* Generic functions: */
static gchar *http_request_xml_escape (gchar * string);

/* INFO REQUEST *************************************************************/
static void http_request_info_process (GString * str, TBGlobal * data,
				       TBProcess * process, guint indent,
				       gint order);

GString *
http_request_info (TBGlobal * data, gchar ** subparts, GList * keyvalue)
{
  GString *str;
  GList *list;

  str = g_string_new (NULL);

  str = g_string_append (str, "<TBControllerInfo>\n");
  str = g_string_append (str, "  <General>\n");
  str =
    g_string_append (str,
		     "    <Server version=\"" VERSION "\">" PACKAGE
		     "</Server>\n");

  g_mutex_lock (data->swap.mutex);

  g_string_append_printf (str,
			  "    <Swap size=\"%" G_GUINT64_FORMAT
			  "\" filesize=\"%" G_GUINT64_FORMAT "\" />\n",
			  data->swap.size, data->swap.filesize);

  g_mutex_unlock (data->swap.mutex);

  str = g_string_append (str, "  </General>\n");

  g_mutex_lock (data->mutex);

  str = g_string_append (str, "  <Processes>\n");

  for (list = data->processes; list; list = list->next)
    {
      TBProcess *process = list->data;

      if (process->global == TRUE)
	http_request_info_process (str, data, process, 0, -1);
    }

  str = g_string_append (str, "  </Processes>\n");

  str = g_string_append (str, "  <Instances>\n");

  for (list = data->istances; list; list = list->next)
    {
      TBIstance *istance = list->data;

      g_string_append_printf (str,
			      "    <Instance id=\"%d\" process=\"%s\">\n",
			      istance->pid, istance->process->id);

      g_string_append_printf (str, "      <Time>%d</Time>\n", istance->time);

      g_string_append_printf (str,
			      "      <IO in=\"%" G_GUINT64_FORMAT
			      "\" out=\"%" G_GUINT64_FORMAT "\" err=\"%"
			      G_GUINT64_FORMAT "\" />\n",
			      io_string_get_size (istance->input),
			      io_string_get_size (istance->output),
			      io_string_get_size (istance->error));

      str = g_string_append (str, "    </Instance>\n");
    }

  str = g_string_append (str, "  </Instances>\n");

  g_mutex_unlock (data->mutex);

  str = g_string_append (str, "</TBControllerInfo>\n");

  return str;
}

static void
http_request_info_process (GString * str, TBGlobal * data,
			   TBProcess * process, guint indent, gint order)
{
  GList *sub;
  gchar *tmp;
  gint i;

  tmp = http_request_xml_escape (process->id);

  for (i = 0; i < indent; i++)
    str = g_string_append (str, "    ");

  g_string_append_printf (str,
			  "    <%sProcess id=\"%s\" multiple=\"%s\" istances=\"%d\"",
			  process->meta == TRUE ? "Meta" : "", tmp,
			  process->multiple == TRUE ? "true" : "false",
			  process->istances);

  g_free (tmp);

  if (order != -1)
    g_string_append_printf (str, " order=\"%d\"", order);

  str = g_string_append (str, ">\n");

  for (i = 0; i < indent; i++)
    str = g_string_append (str, "    ");

  g_string_append_printf (str,
			  "      <Istances running=\"%d\" wait=\"%d\" />\n",
			  process->istances_running,
			  process->istances_wait_numb);

  tmp = http_request_xml_escape (process->command);

  for (i = 0; i < indent; i++)
    str = g_string_append (str, "    ");

  g_string_append_printf (str,
			  "      <Command inline=\"%s\">%s</Command>\n",
			  process->command_inline ==
			  TRUE ? "true" : "false", tmp);

  g_free (tmp);

  for (i = 0; i < indent; i++)
    str = g_string_append (str, "    ");

  str = g_string_append (str, "      <Processes>\n");

  for (sub = process->processes; sub; sub = sub->next)
    {
      TBSubProcess *sp = sub->data;
      TBProcess *global = NULL;
      GList *find;

      for (find = data->processes; find; find = find->next)
	{
	  TBProcess *findp = find->data;

	  if (!g_utf8_collate (findp->id, sp->process))
	    {
	      if (findp->global == FALSE)
		global = findp;

	      break;
	    }
	}

      if (!global)
	{
	  for (i = 0; i < indent; i++)
	    str = g_string_append (str, "    ");

	  tmp = http_request_xml_escape (sp->process);

	  g_string_append_printf (str,
				  "        <Process id=\"%s\" order=\"%d\" />\n",
				  tmp, sp->order);

	  g_free (tmp);
	}

      else
	http_request_info_process (str, data, global, indent + 1, sp->order);
    }

  for (i = 0; i < indent; i++)
    str = g_string_append (str, "    ");
  str = g_string_append (str, "      </Processes>\n");

  for (i = 0; i < indent; i++)
    str = g_string_append (str, "    ");
  str = g_string_append (str, "    </Process>\n");
}

/* LIST **********************************************************************/
static GString *
http_request_list (TBGlobal * data, gchar ** subparts, GList * keyvalue)
{
  static GString *static_list = NULL;
  GList *list;

  /* Static generation of the list: */
  if (static_list == NULL)
    {
      static_list = g_string_new (NULL);

      static_list = g_string_append (static_list, "<TBControllerList>\n");

      g_mutex_lock (data->mutex);

      for (list = data->processes; list; list = list->next)
	{
	  TBProcess *process = list->data;
	  gchar *tmp;

	  if (process->global == FALSE || process->hidden == TRUE)
	    continue;

	  tmp = http_request_xml_escape (process->id);

	  g_string_append_printf (static_list, "  <Process id=\"%s\"/>\n",
				  tmp);

	  g_free (tmp);
	}

      g_mutex_unlock (data->mutex);

      static_list = g_string_append (static_list, "</TBControllerList>\n");
    }

  return g_string_new (static_list->str);
}

/* EXEC **********************************************************************/
static GString *
http_request_exec (TBGlobal * data, gchar ** subparts, GList * keyvalue)
{
  GList *list;
  GString *str;
  gboolean done = FALSE;

  if (!subparts || !subparts[0] || !subparts[1] || subparts[2])
    return NULL;

  g_mutex_lock (data->mutex);

  for (list = data->processes; list; list = list->next)
    {
      TBProcess *process = list->data;

      if (!g_utf8_collate (subparts[1], process->id))
	{
	  process->is_to_schedule = TRUE;
	  done = TRUE;
	  break;
	}
    }

  g_mutex_unlock (data->mutex);

  str = g_string_new (NULL);
  str = g_string_append (str, "<TBControllerExec>\n");

  if (done == FALSE)
    {
      gchar *tmp;

      tmp = http_request_xml_escape (subparts[1]);

      g_string_append_printf (str,
			      "  <Error>Process '%s' doesn't exist</Error>\n",
			      tmp);

      g_free (tmp);
    }

  else
    str = g_string_append (str, "  <Status>Ok</Status>\n");

  str = g_string_append (str, "</TBControllerExec>\n");

  return str;
}

#ifdef TB_DEBUG
/* DEBUG *********************************************************************/
static GString *
http_request_debug (TBGlobal * data, gchar ** subparts, GList * keyvalue)
{
  GString *str;
  GList *list;

  str = g_string_new (NULL);
  str = g_string_append (str, "<TBControllerDebug>\n");

  g_static_mutex_lock (&debug_mutex);

  str = g_string_append (str, "  <messages>\n");

  for (list = debug_strings; list; list = list->next)
    {
      TBDebug *db = list->data;
      gchar buf[26];
      gint i;

      ctime_r (&db->time, buf);

      for (i = sizeof (buf) - 1; i > 0; i--)
	{
	  if (buf[i] == '\n')
	    {
	      buf[i] = 0;
	      break;
	    }
	}

      g_string_append_printf (str,
			      "    <status time=\"%s\" repeat=\"%d\">%s</status>\n",
			      buf, db->repeat, db->message);
    }

  str = g_string_append (str, "  </messages>\n");

  g_static_mutex_unlock (&debug_mutex);

  str = g_string_append (str, "</TBControllerDebug>\n");

  return str;
}
#endif

/* GENERIC FUNCTIONS ********************************************************/
static gchar *
http_request_xml_escape (gchar * string)
{
  GString *ret;
  gunichar unichr;

  ret = g_string_new (NULL);

  while ((unichr = g_utf8_get_char (string)))
    {
      string = g_utf8_next_char (string);

      switch (unichr)
	{
	case '\'':
	  ret = g_string_append (ret, "&apos;");
	  break;

	case '"':
	  ret = g_string_append (ret, "&quot;");
	  break;

	default:
	  ret = g_string_append_unichar (ret, unichr);
	  break;
	}
    }

  return g_string_free (ret, FALSE);
}

/* EOF */
